package impl.gui.listeners;

import impl.core.UDecideManager;
import impl.events.ChoiceClassExpressionSetEvent;
import impl.events.UtilityAssertionAddedEvent;
import impl.events.UtilityAssertionChangedEvent;
import impl.events.uBoxChanges.UBoxLoadedChange;
import impl.events.uBoxChanges.UBoxSavedChange;
import impl.gui.UDecideGUI;
import impl.io.UDecideIO;
import impl.io.UDecideIO.OntologyFormat;
import impl.reasoning.UDecideReasonerFactory;
import impl.util.UDecideLog;
import impl.util.UtilityAssertion;
import impl.util.messages.InfoMessages;
import interfaces.ClassExpressionAcceptedListenerInterface;
import interfaces.abstracts.AbstractClassExpressionAcceptedEvent;

import java.awt.Cursor;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Collection;

import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.filechooser.FileNameExtensionFilter;

import exceptions.UDecideReasonerConnectionException;
import exceptions.UDecideReasonerRuntimeException;
import exceptions.UDecideUBoxLoadException;
import exceptions.UDecideUBoxSaveException;

public class UDecideGUIListener implements ActionListener, ClassExpressionAcceptedListenerInterface {

	private static UDecideGUIListener	instance;
	private UDecideGUI					gui;

	@Override
	public void actionPerformed(ActionEvent e) {
		switch (e.getActionCommand()) {
			case "clearUBox":
				UDecideManager.getInstance().clearUBox();
				break;
			case "loadUBox":
				loadUBox();
				break;
			case "saveUBox":
				saveUBox();
				break;
			case "startCalculation":
				startCalculation();
				break;
			case "showUAssertionDialog":
				this.gui.showUtilityAssertionDialog();
				break;
			case "removeUAssertions":
				UDecideManager.getInstance().removeUtilityAssertions(this.gui.getSelectedUtilityAssertions());
				break;
		}
	}

	private void startCalculation() {
		final JDialog infoDialog = new JDialog();

		Thread queryThread = new Thread() {
			@Override
			public void run() {
				try {
					UDecideManager.getInstance().prepareReasoner();
					UDecideGUIListener.this.gui.updateUtilityReasoningResults();
				} catch (UDecideReasonerConnectionException | UDecideReasonerRuntimeException ex) {
					UDecideLog.error(ex.toString());
				} finally {
					SwingUtilities.invokeLater(new Runnable() {
						@Override
						public void run() {
							infoDialog.setVisible(false);
						}
					});
				}
			}
		};

		try {
			final JOptionPane infoOptionPane = new JOptionPane("Connecting to Konclude server on address: " + UDecideReasonerFactory.getServerAddress()
					+ "\n" + "This may take up to 10 seconds.", JOptionPane.INFORMATION_MESSAGE, JOptionPane.DEFAULT_OPTION, null, new Object[] {}, null);

			infoDialog.setTitle("Connecting to Konclude reasoner");
			infoDialog.setModal(true);

			infoDialog.setContentPane(infoOptionPane);

			infoDialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
			infoDialog.pack();
			infoDialog.setLocation(((Toolkit.getDefaultToolkit().getScreenSize().width) / 2) - (infoDialog.getWidth() / 2), ((Toolkit.getDefaultToolkit()
					.getScreenSize().height) / 2) - (infoDialog.getHeight() / 2));

			// set busy cursor
			infoDialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
			queryThread.start();
			infoDialog.setVisible(true);

		} finally {
			infoDialog.setCursor(Cursor.getDefaultCursor());
			infoDialog.dispose();
		}

	}

	private void loadUBox() {
		JFileChooser fc = new JFileChooser(UDecideIO.folderPath);
		FileNameExtensionFilter filter = new FileNameExtensionFilter("uBox OWL ontology", "owl");
		fc.setFileFilter(filter);
		int returnVal = fc.showOpenDialog(this.gui);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			try {
				File f = fc.getSelectedFile();

				if (!f.toString().endsWith(".owl")) {
					f = new File(f.toString() + ".owl");
				}

				Collection<UtilityAssertion> utilityAssertions = UDecideIO.loadUtilityAssertionsFromFile(f);

				UDecideManager.getInstance().loadUBoxFromUtilityAssertions(utilityAssertions);

				UDecideLog.info(InfoMessages.UBOX_LOADED.toString() + fc.getSelectedFile());

				this.gui.UBoxChanged(new UBoxLoadedChange(utilityAssertions, f.getAbsolutePath()));

				// set pathReminder
				String selectedDirectory = fc.getSelectedFile().getParent();
				if (selectedDirectory != null) {
					UDecideIO.folderPath = selectedDirectory;
				}
			} catch (UDecideUBoxLoadException ex) {
				UDecideLog.error(ex.toString());
			}
		}
	}

	private void saveUBox() {
		final JFileChooser fc = new JFileChooser(UDecideIO.folderPath);
		FileNameExtensionFilter filter = new FileNameExtensionFilter("uBox OWL ontology", "owl");
		fc.setFileFilter(filter);

		int returnVal = fc.showSaveDialog(this.gui);

		if (returnVal == JFileChooser.APPROVE_OPTION) {
			try {
				File f = fc.getSelectedFile();

				if (!f.toString().endsWith(".owl")) {
					f = new File(f.toString() + ".owl");
				}

				UDecideIO.saveUBoxToFile(UDecideManager.getInstance().getUBox(), f, OntologyFormat.OWLXML);

				UDecideLog.info(InfoMessages.UBOX_SAVED.toString() + f.getAbsolutePath());

				this.gui.UBoxChanged(new UBoxSavedChange(fc.getSelectedFile().getAbsolutePath()));

				// set pathReminder
				String selectedDirectory = fc.getSelectedFile().getParent();
				if (selectedDirectory != null) {
					UDecideIO.folderPath = selectedDirectory;
				}
			} catch (UDecideUBoxSaveException e) {
				UDecideLog.error(e.toString());
			}
		}

	}

	public UDecideGUIListener(UDecideGUI gui) {
		this.gui = gui;
		instance = this;
	}

	public static UDecideGUIListener getInstance() {
		return instance;
	}

	@Override
	public void classExpressionAccepted(AbstractClassExpressionAcceptedEvent e) {
		if (e instanceof UtilityAssertionAddedEvent) {
			UtilityAssertion uAssertion = UDecideManager.getInstance().getUDecideParser()
					.parseUtilityAssertion(e.getClassExpressionString(), ((UtilityAssertionAddedEvent) e).getUtilityValueString());
			UDecideManager.getInstance().addUtilityAssertion(uAssertion);
		} else if (e instanceof ChoiceClassExpressionSetEvent) {
			UDecideManager.getInstance().setChoiceClassExpression(
					UDecideManager.getInstance().getUDecideParser().parseOWLClassExpression(e.getClassExpressionString()));
		}
	}

	public void utilityAssertionChanged(UtilityAssertionChangedEvent utilityValueChangedEvent) {
		UtilityAssertion newUtilityAssertion = UDecideManager.getInstance().getUDecideParser()
				.parseUtilityAssertion(utilityValueChangedEvent.getClassExpressionString(), utilityValueChangedEvent.getUtilityValueString());
		UDecideManager.getInstance().editUtilityAssertion(utilityValueChangedEvent.getUtilityAssertion(), newUtilityAssertion);
	}
}
